require 'rspec/core'
require 'rspec/core/rake_task'
require 'json'
require 'yaml'
require 'fileutils'

# Config files
$intrigue_basedir = File.dirname(__FILE__)
$intrigue_environment = "development"

# Configuration and scripts
puma_config_file = "#{$intrigue_basedir}/config/puma.rb"
system_config_file = "#{$intrigue_basedir}/config/config.json"
database_config_file = "#{$intrigue_basedir}/config/database.yml"
sidekiq_config_file = "#{$intrigue_basedir}/config/sidekiq.yml"
redis_config_file = "#{$intrigue_basedir}/config/redis.yml"
control_script = "#{$intrigue_basedir}/util/control.sh"

all_config_files = [
  puma_config_file,
  system_config_file,
  database_config_file,
  sidekiq_config_file,
  redis_config_file
]

desc "Clean"
task :clean do
  puts "[+] Cleaning up!"
  all_config_files.each do |c|
    FileUtils.mv c, "#{c}.backup"
  end
end

desc "System Setup"
task :setup do

  puts "[+] Setup initiated!"

  ## Copy puma config into place
  puts "[+] Copying puma config...."
  if File.exist? puma_config_file
    puts "[ ] File already exists, skipping: #{puma_config_file}"
  else
    puts "[+] Creating.... #{puma_config_file}"
    FileUtils.cp "#{puma_config_file}.default", puma_config_file
  end

  ## Copy system config into place
  puts "[+] Copying system config...."

  if File.exist? system_config_file

    puts "[ ] File already exists, skipping: #{system_config_file}"
    config = JSON.parse(File.read(system_config_file))
    system_password = config["credentials"]["password"]

  else
    puts "[+] Creating system config: #{system_config_file}"
    FileUtils.cp "#{system_config_file}.default", system_config_file

    # Set up our password
    config = JSON.parse(File.read(system_config_file))
    if config["credentials"]["password"] == "AUTOGENERATED"
      # generate a new password
      system_password = "#{(0...11).map { ('a'..'z').to_a[rand(26)] }.join}"
      puts "[+] GENERATING NEW SYSTEM PASSWORD!"
      # Save it
      config["credentials"]["password"] = system_password
      File.open(system_config_file,"w").puts JSON.pretty_generate(config)
    else
      system_password = config["credentials"]["password"]
    end

  end

  # Print it
  puts "[+]"
  puts "[+] SYSTEM PASSWORD: #{system_password}"
  puts "[+]"

  ## Copy database config into place
  puts "[+] Copying database config...."
  if File.exist? database_config_file
    puts "[ ] File already exists, skipping: #{database_config_file}"
  else
    puts "[+] Creating.... #{database_config_file}"
    FileUtils.cp "#{database_config_file}.default", database_config_file

    # Set up our password
    config = YAML.load_file(database_config_file)
    config["development"]["password"] = system_password
    config["production"]["password"] = system_password
    config["docker"]["password"] = system_password
    File.open(database_config_file,"w").puts YAML.dump config
  end

  ## Copy redis config into place
  puts "[+] Copying redis config...."
  if File.exist? redis_config_file
    puts "[ ] File already exists, skipping: #{redis_config_file}"
  else
    puts "[+] Creating.... #{redis_config_file}"
    FileUtils.cp "#{redis_config_file}.default", redis_config_file
  end

  ## Place sidekiq task worker configs into place
  puts "[+] Setting up sidekiq config...."
  worker_configs = [
    sidekiq_config_file
  ]

  worker_configs.each do |wc|
    unless File.exist?(wc)
      puts "[+] Copying: #{wc}.default"
      FileUtils.cp "#{wc}.default", wc
    else
      puts "[+] #{wc} already exists!"
    end
  end
  # end worker config placement

  puts "[+] Downloading latest data files..."
  Dir.chdir("#{$intrigue_basedir}/data/"){ puts %x["./get_latest.sh"] }

  ## Copy control script
  puts "[+] Copying control script..."
  if File.exist? control_script
    puts "[ ] File already exists, skipping: #{control_script}"
  else
    puts "[+] Creating.... #{control_script}"
    FileUtils.cp "#{control_script}.default", control_script

    # Configure the IDIR directory
    script_text = File.read(control_script)
    new_script_text = script_text.gsub("IDIR=/core","IDIR=#{$intrigue_basedir}")
    File.open(control_script,"w").puts new_script_text

    # Make a link
    # TODO - this should be deprecated.
    if Dir.exist?("/etc/init.d") && !File.exist?("#{$intrigue_basedir}/util/control.sh")
      puts '[+] Creating system-level startup script'
      `ln -s #{$intrigue_basedir}/util/control.sh /etc/init.d/intrigue`
    end

  end

  puts "[+] Complete!"

end

desc "Reset Workers"
task :reset_workers do
  puts "[ ] Resetting workers"
  require './core'
  Intrigue::Model::Project.all.each do |p|
    puts "[+] Clean state for #{p.name}"
    p.graph_generation_in_progress=false
    p.save
  end
end

#desc "Run Specs"
#task :spec do
#end

#desc "Run Integration Specs (requires API running)"
#task :integration do
#  t.rspec_opts = "--pattern spec/integration/*_spec.rb"
#end


# database set up
def setup_database
  require "sequel"

  options = {
    :max_connections => 16,
    :pool_timeout => 240
  }

  database_config = YAML.load_file("#{$intrigue_basedir}/config/database.yml")
  database_host = database_config[$intrigue_environment]["host"] || "localhost"
  database_port = database_config[$intrigue_environment]["port"] || 5432
  database_user = database_config[$intrigue_environment]["user"]
  database_pass = database_config[$intrigue_environment]["pass"]
  database_name = database_config[$intrigue_environment]["database"]
  database_debug = database_config[$intrigue_environment]["debug"]

  $db = Sequel.connect("postgres://#{database_user}@#{database_host}:#{database_port}/#{database_name}", options)
  $db.loggers << Logger.new($stdout) if database_debug

  # Allow datasets to be paginated
  $db.extension :pagination
  Sequel.extension :pg_json_ops
  Sequel.extension :migration
end


namespace :db do
  desc "Prints current schema version"
  task :version do
    setup_database
    version = if $db.tables.include?(:schema_info)
      $db[:schema_info].first[:version]
    end || 0
    puts "[+] Schema Version: #{version}"
  end

  desc "Perform migration up to latest migration available"
  task :migrate do
    setup_database
    Sequel::Migrator.run($db, "db")
    Rake::Task['db:version'].execute
  end

  desc "Perform rollback to specified target or full rollback as default"
  task :rollback, :target do |t, args|
    setup_database
    args.with_defaults(:target => 0)
    Sequel::Migrator.run($db, "db", :target => args[:target].to_i)
    Rake::Task['db:version'].execute
  end

  desc "Perform migration reset (full rollback and migration)"
  task :reset do
    setup_database
    Sequel::Migrator.run($db, "db", :target => 0)
    Sequel::Migrator.run($db, "db")
    Rake::Task['db:version'].execute
  end
end
